package com.innotek.testworkstation.common.restassured.testcase;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.innotek.testworkstation.common.restassured.apipage.ApisStart;
import com.innotek.testworkstation.util.BuiltFunctionUtils;
import com.innotek.testworkstation.util.CachePool;
import com.innotek.testworkstation.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 代表的是测试用例，提供读取测试用例、执行功能
 */
public class TestCaseModel {
    public String name = "";
    public String description = "";
    public String tag = "all";
    public List<CaseStepModel> steps;

    /**
     * 加载一个yaml文件，并转成测试用例的模型类
     *
     * @param path 测试用例的yaml文件路径
     * @return
     */
    public static TestCaseModel loadCase(String path) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
        return objectMapper.readValue(new File(path), TestCaseModel.class);
    }


    /**
     * 借助于runCase，去运行对应的测试用例，主要是运行其中的测试步骤steps，以及断言。
     *
     * @param apisStart
     */
    public void start(ApisStart apisStart) {
        steps.forEach(step -> {
            // 请求参数map
            HashMap<String, Object> paramsMap = step.params;
            if(paramsMap != null) {
                paramsMap.forEach((key, value) -> {
                    // 先替换已有变量
                    value = getValueForCaseParam(value);
                    // 内置程序替换
                    value = fomatForFunction(value);

                    paramsMap.put(key,value);
                });
                step.params = paramsMap;
            }
            
            // 如果有验证，遍历下是否有变量，有的则替换
            List<HashMap<String,Object>> verifyListMap = step.verify;
            if(verifyListMap != null){
                verifyListMap.forEach(verfyMap->{
                    verfyMap.forEach((key, value)->{
                        verfyMap.put(key,fomatForFunction(getValueForCaseParam(value)));
                    });
                });
                step.verify = verifyListMap;
            }

            apisStart.start(step);

        });
    }

    /**
     * 内置方法替换测试用例的参数
     */
    private Object fomatForFunction(Object value){
        // 再检查是否有需要调用内置函数
        ArrayList<String> functionInfo = getFunctionInfoForRegular(value.toString());
        if (functionInfo != null) {
            String formatStr = functionInfo.get(0).trim();
            String functionName = functionInfo.get(1).trim();
            String param = functionInfo.get(2).trim();
            if (functionName.equals("__getStringRandom")) {
                // 获取随机字符串方法
                String radStr = BuiltFunctionUtils.getStringRandom(Integer.parseInt(param));
                value = value.toString().replace(formatStr, radStr);
            }else if(functionName.equals("__getStringRandomToUpperCase")){
                // 获取随机字符串方法(字母都大写)
                String radStr = BuiltFunctionUtils.getStringRandomToUpperCase(Integer.parseInt(param));
                value = value.toString().replace(formatStr, radStr);
            }else if(functionName.equals("__nowTime")){
                // 获取当前日期和时间
                String formatTimes = BuiltFunctionUtils.nowTime(param);
                value = value.toString().replace(formatStr, formatTimes);
            }else if(functionName.equals("__timeShift")){
                // 当前时间为基础，加减时间后的时间；
                // 多个参数用,号分割取值
                String[] p = param.split(",");
                String timeShiftStr;
                if(p.length < 2 ){
                    timeShiftStr = BuiltFunctionUtils.timeShift(p[0].trim(),"");
                }else{
                    timeShiftStr = BuiltFunctionUtils.timeShift(p[0].trim(),p[1].trim());
                }
                value = value.toString().replace(formatStr, timeShiftStr);

            }else if(functionName.equals("__stringToInt")){
                // 字符串转int
                value = BuiltFunctionUtils.stringToInt(param);
            }else if(functionName.equals("__getRandomRange")){
                // 获取随机数字
                // 多个参数用,号分割取值
                String[] p = param.split(",");
                value =BuiltFunctionUtils.getRandomRange(Integer.parseInt(p[0]), Integer.parseInt(p[1]));

            }
            // TODO 待补充其他内置方法
        }
        return value;
    }


    /**
     * 字符串中如果有__XXX()格式的，则通过正则取出
     * @param str 要正则匹配的字符串
     * @return  返回找到的方法、方法名称、参数
     */
    private ArrayList<String> getFunctionInfoForRegular(String str) {
        String pattern = "(__[^_].*?)\\((.*?)\\)";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(str);
        ArrayList<String> result = new ArrayList<>();
        if (m.find()) {
            result.add(m.group(0));
            result.add(m.group(1));
            result.add(m.group(2));
        } else {
            return null;
        }
        return result;
    }

    /**
     * 去临时文件里匹配是否有相应key，若有，则替换
     * @param value 变量值
     * @return 若找到，则返回真实的值
     */
    private Object getValueForCaseParam(Object value) {
        if (value.toString().contains("${")) {
            // 包含"${"说明需要替换变量
            Map<String, Object> ptu = CachePool.getInstance().getCacheItems();
            String param = StringUtils.regexForOne("\\$\\{(.*?)\\}", value.toString());
            if (param != null) {
                Object realValue = ptu.get(param);
                if (realValue != null) {
                    // 把变量值替换成临时文件里值,可从中间替换
                    String matcher = "${" + param + "}";
                    value = value.toString().replace(matcher, realValue.toString());
                }
            }
        }
        return value;
    }

}
